/*
 * @Author: dgflash
 * @Date: 2022-05-12 14:18:44
 * @LastEditors: dgflash
 * @LastEditTime: 2022-05-24 11:09:49
 * 
 * 优化说明：
 * 1. 使用 32 位而不是 31 位（充分利用 Uint32Array）
 * 2. 使用位运算常量预计算（避免重复计算）
 * 3. 优化热路径方法（减少函数调用和计算）
 * 4. 添加内联注释提示 V8 优化
 * 5. 使用无符号右移确保正数
 */
import { ECSModel } from "./ECSModel";

/**
 * ECS 位掩码（Bitmask）- 高性能版本
 * 
 * 用于标记实体拥有哪些组件，支持快速查询和比较
 * 
 * 优化要点：
 * - 使用 32 位掩码（而非 31 位）充分利用 Uint32Array
 * - 位运算常量预计算
 * - 减少除法和取模运算
 * - 优化循环和早期退出
 */
export class ECSMask {
    private mask: Uint32Array;
    private size: number;
    
    // 优化：预计算的常量，避免重复计算
    private static readonly BITS_PER_ELEMENT = 32;
    private static readonly BITS_SHIFT = 5;  // log2(32) = 5，用于快速除以 32
    private static readonly BITS_MASK = 31;  // 32 - 1，用于快速取模
    
    constructor() {
        // 优化：使用位移代替除法（更快）
        // Math.ceil(compTid / 32) 等价于 (compTid + 31) >> 5
        const length = ((ECSModel.compTid + 31) >>> ECSMask.BITS_SHIFT) || 1;
        this.mask = new Uint32Array(length);
        this.size = length;
    }
    
    /**
     * 设置指定位
     * @param num 组件 ID
     * 
     * 优化：
     * - 使用右移代替除法（num >> 5 代替 num / 32）
     * - 使用按位与代替取模（num & 31 代替 num % 32）
     * - 无符号右移确保正数
     */
    set(num: number): void {
        // index = num >> 5 (等价于 Math.floor(num / 32))
        // bit = num & 31 (等价于 num % 32)
        this.mask[num >>> ECSMask.BITS_SHIFT] |= (1 << (num & ECSMask.BITS_MASK));
    }
    
    /**
     * 删除指定位
     * @param num 组件 ID
     */
    delete(num: number): void {
        this.mask[num >>> ECSMask.BITS_SHIFT] &= ~(1 << (num & ECSMask.BITS_MASK));
    }
    
    /**
     * 检查是否包含指定位
     * @param num 组件 ID
     * @returns 是否包含
     * 
     * 优化：直接返回布尔值，避免双重取反
     */
    has(num: number): boolean {
        return (this.mask[num >>> ECSMask.BITS_SHIFT] & (1 << (num & ECSMask.BITS_MASK))) !== 0;
    }
    
    /**
     * OR 操作：检查两个掩码是否有任何交集
     * @param other 另一个掩码
     * @returns 是否有交集
     * 
     * 优化：
     * - 使用 Math.min 避免越界
     * - 早期退出优化
     */
    or(other: ECSMask): boolean {
        // 优化：只检查较小的 size，避免越界
        const minSize = Math.min(this.size, other.size);
        
        // 优化：早期退出 - 找到第一个匹配就返回
        for (let i = 0; i < minSize; i++) {
            if (this.mask[i] & other.mask[i]) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * AND 操作：检查 this 是否包含 other 的所有位
     * @param other 另一个掩码
     * @returns this 是否包含 other 的所有位
     * 
     * 优化：
     * - 早期退出优化
     * - 减少不必要的比较
     */
    and(other: ECSMask): boolean {
        // 优化：只检查 other 的 size
        const checkSize = Math.min(this.size, other.size);
        
        // 优化：早期退出 - 发现不匹配立即返回
        for (let i = 0; i < checkSize; i++) {
            if ((this.mask[i] & other.mask[i]) !== this.mask[i]) {
                return false;
            }
        }
        
        // 优化：如果 this 更大，检查剩余部分是否全为 0
        for (let i = checkSize; i < this.size; i++) {
            if (this.mask[i] !== 0) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 清空所有位
     * 
     * 优化：使用 fill 方法，比循环更快
     */
    clear(): void {
        // 优化：TypedArray.fill 通常比循环更快
        this.mask.fill(0);
    }
    
    /**
     * 复制掩码
     * @param other 源掩码
     * 
     * 新增：高效复制方法
     */
    copy(other: ECSMask): void {
        // 确保大小相同
        if (this.size !== other.size) {
            this.mask = new Uint32Array(other.size);
            this.size = other.size;
        }
        
        // 使用 set 方法批量复制，比循环快
        this.mask.set(other.mask);
    }
    
    /**
     * 检查是否为空（所有位都是 0）
     * @returns 是否为空
     * 
     * 新增：常用的检查方法
     */
    isEmpty(): boolean {
        for (let i = 0; i < this.size; i++) {
            if (this.mask[i] !== 0) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * 获取设置的位数量
     * @returns 位数量
     * 
     * 新增：调试和统计用
     */
    count(): number {
        let count = 0;
        for (let i = 0; i < this.size; i++) {
            // 使用 Brian Kernighan 算法计算位数
            let n = this.mask[i];
            while (n) {
                n &= n - 1;  // 清除最低位的 1
                count++;
            }
        }
        return count;
    }
    
    /**
     * 获取所有设置的位（组件 ID）
     * @returns 组件 ID 数组
     * 
     * 新增：调试用
     */
    getIndices(): number[] {
        const indices: number[] = [];
        for (let i = 0; i < this.size; i++) {
            let n = this.mask[i];
            if (n === 0) continue;
            
            const baseIndex = i << ECSMask.BITS_SHIFT;  // i * 32
            for (let bit = 0; bit < ECSMask.BITS_PER_ELEMENT; bit++) {
                if (n & (1 << bit)) {
                    indices.push(baseIndex + bit);
                }
            }
        }
        return indices;
    }
}